package com.i2works.smartluolong.utils.common;

import com.alibaba.simpleimage.ImageFormat;
import com.alibaba.simpleimage.ImageWrapper;
import com.alibaba.simpleimage.render.CropParameter;
import com.alibaba.simpleimage.render.ScaleParameter;
import com.alibaba.simpleimage.render.WatermarkParameter;
import com.alibaba.simpleimage.render.WriteParameter;
import com.alibaba.simpleimage.util.*;
import com.i2works.smartluolong.utils.base.ImageConstant;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;

import javax.imageio.ImageIO;
import javax.media.jai.PlanarImage;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * simpleimage 工具类
 * 阿里巴巴 simpleimage 图片处理工具类 功能 等比例缩放 裁切 加水印 复合操作
 *
 * @author Liu Yutao <koal@vip.qq.com>
 * @date 2018/9/11 19:23
 */

public class ImageUtil {

    /**
     * 日志记录
     */
    protected static final Logger logger = LoggerFactory.getLogger(ImageUtil.class);

    /**
     * 图片格式化类型
     */
    private static ImageFormat outputFormat = ImageFormat.JPEG;

    public static void main(String[] args) {
//         1.等比例缩放
//        scaleNormal("D:\\data\\src.jpg", "D:\\data\\scaleNormal.jpg", 300, 200);
//         2.等比例缩放加水印
//        scaleWithWaterMark("D:\\data\\src.jpg", "D:\\data\\scaleWithWaterMark.jpg", 300, 200);
//         3.缩放到指定宽度
//        scaleWithWidth("D:\\data\\src.jpg", "D:\\data\\scaleWithWidth.jpg", 320);
////         4.缩放到指定高度
//        scaleWithHeight("D:\\data\\src.jpg", "D:\\data\\scaleWithHeight.jpg", 600);
////         5.裁切成正方形
//        cut("D:\\data\\src.jpg", "D:\\data\\cut.jpg");
////         6.从中间裁切
//        cutCenter("D:\\data\\src.jpg", "D:\\data\\cutCenter.jpg", 600, 800);


    }

    /**
     * 是否为图片
     */
    public static boolean isPicture(String pInput, String pImgeFlag) {
        if (StringUtils.isBlank(pInput)) {
            return false;
        }
        String tmpName = pInput.substring(pInput.lastIndexOf(".") + 1, pInput.length());
        String imgeArray[][] = {{"bmp", "0"}, {"dib", "1"}, {"gif", "2"}, {"jfif", "3"}, {"jpe", "4"}, {"jpeg", "5"}, {"jpg", "6"}, {"png", "7"}, {"tif", "8"}, {"tiff", "9"}, {"ico", "10"}};
        for (String[] anImgeArray : imgeArray) {
            if (!StringUtils.isBlank(pImgeFlag) && anImgeArray[0].equals(tmpName.toLowerCase()) && anImgeArray[1].equals(pImgeFlag)) {
                return true;
            }
            if (StringUtils.isBlank(pImgeFlag) && anImgeArray[0].equals(tmpName.toLowerCase())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 等比例缩放(会裁切部分内容)
     *
     * @param src    源文件
     * @param target 目标文件
     * @param width  宽度
     * @param height 高度
     */
    public static void scale(String src, String target, int width, int height) {
        File out = new File(target); // 目的图片
        FileOutputStream outStream = null;
        File in = new File(src); // 原图片
        FileInputStream inStream = null;
        try {
            inStream = new FileInputStream(in);
            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);
            int w = imageWrapper.getWidth();
            int h = imageWrapper.getHeight();

            float w1, h1;
            float sp = (float) w / h;
            float rp = (float) width / height;
            if (sp > rp) {
                w1 = (width * h) / (float) w;
                h1 = width;

            } else if (sp < rp) {
                h1 = (height * w) / (float) h;
                w1 = width;
            } else {
                w1 = width;
                h1 = height;
            }

            // 1.缩放
            ScaleParameter scaleParam = new ScaleParameter((int) w1, (int) h1, ScaleParameter.Algorithm.LANCZOS); // 缩放参数
            PlanarImage planrImage = ImageScaleHelper.scale(imageWrapper.getAsPlanarImage(), scaleParam);
            imageWrapper = new ImageWrapper(planrImage);
            // 4.输出
            outStream = new FileOutputStream(out);
            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
        } catch (Exception e) {
            logger.error("simpleImageUtil.scale异常:" + e.getMessage());
        } finally {
            // 图片文件输入输出流必须记得关闭
            IOUtils.closeQuietly(inStream);
            IOUtils.closeQuietly(outStream);
        }
    }

    /**
     * 正常缩放
     *
     * @param src    源文件
     * @param target 目标文件
     * @param width  宽度
     * @param height 高度
     */
    @SuppressWarnings("Duplicates")
    public static void scaleNormal(String src, String target, int width, int height) {
        File out = new File(target); // 目的图片
        FileOutputStream outStream = null;
        File in = new File(src); // 原图片
        FileInputStream inStream = null;
        try {
            inStream = new FileInputStream(in);
            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);
            int w = imageWrapper.getWidth();
            int h = imageWrapper.getHeight();
            int cw = w, ch = h, x = 0, y = 0;
            boolean isDeal = true;
            if (height > h || width > w) {
                isDeal = false;
            } else if ((w - width) > (h - height)) {
                ch = h;
                cw = (h * width) / height;
                x = (w - cw) / 2;
                if (cw > h) {
                    cw = w;
                    ch = (w * height) / width;
                    y = (h - ch) / 2;
                    x = 0;
                }

            } else if ((w - width) <= (h - height)) {
                cw = w;
                ch = (w * height) / width;
                y = (h - ch) / 2;
                if (ch > h) {
                    ch = h;
                    cw = (h * width) / height;
                    x = (w - cw) / 2;
                    y = 0;
                }
            }
            logger.info("x: " + x + " y" + y + "cw: " + cw + " ch" + ch + "");
            if (isDeal) {
                CropParameter cropParam = new CropParameter(x, y, cw, ch);// 裁切参数
                PlanarImage planrImage = ImageCropHelper.crop(imageWrapper.getAsPlanarImage(), cropParam);
                ScaleParameter scaleParam = new ScaleParameter(width, height, ScaleParameter.Algorithm.LANCZOS); // 缩放参数
                planrImage = ImageScaleHelper.scale(planrImage, scaleParam);
                imageWrapper = new ImageWrapper(planrImage);
            }
            // 4.输出
            outStream = new FileOutputStream(out);
            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
        } catch (Exception e) {
            logger.error("simpleImageUtil.scaleNormal异常:" + e.getMessage());
        } finally {
            IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
            IOUtils.closeQuietly(outStream);

        }
    }

    /**
     * 压缩图片到指定尺寸(图片比目标图片小则不会变形(有水印）)
     *
     * @param src    源文件
     * @param target 目标文件
     * @param width  宽度
     * @param height 高度
     */
    @SuppressWarnings("Duplicates")
    public static void scaleWithWaterMark(String src, String target, int width, int height) {
        File out = new File(target); // 目的图片
        FileOutputStream outStream = null;
        File in = new File(src); // 原图片
        FileInputStream inStream = null;
        try {
            inStream = new FileInputStream(in);
            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);
            int w = imageWrapper.getWidth();
            int h = imageWrapper.getHeight();
            int cw = w, ch = h, x = 0, y = 0;
            boolean isDeal = true;
            if (height > h || width > w) {
                isDeal = false;
            } else if ((w - width) > (h - height)) {
                ch = h;
                cw = (h * width) / height;
                x = (w - cw) / 2;
                if (cw > h) {
                    cw = w;
                    ch = (w * height) / width;
                    y = (h - ch) / 2;
                    x = 0;
                }

            } else if ((w - width) <= (h - height)) {
                cw = w;
                ch = (w * height) / width;
                y = (h - ch) / 2;
                if (ch > h) {
                    ch = h;
                    cw = (h * width) / height;
                    x = (w - cw) / 2;
                    y = 0;
                }
            }
            //System.out.println("x: " + x + " y" + y + "cw: " + cw + " ch" + ch + "");
            if (isDeal) {
                CropParameter cropParam = new CropParameter(x, y, cw, ch);// 裁切参数
                PlanarImage planrImage = ImageCropHelper.crop(imageWrapper.getAsPlanarImage(), cropParam);
                ScaleParameter scaleParam = new ScaleParameter(width, height, ScaleParameter.Algorithm.LANCZOS); // 缩放参数
                planrImage = ImageScaleHelper.scale(planrImage, scaleParam);
                imageWrapper = new ImageWrapper(planrImage);
            }
            // 3.打水印
            BufferedImage waterImage = ImageIO.read(new File(ResourceUtils.CLASSPATH_URL_PREFIX + ImageConstant.WATERMARK_URL));
            ImageWrapper waterWrapper = new ImageWrapper(waterImage);
            Point p = calculate(imageWrapper.getWidth(), imageWrapper.getHeight(), waterWrapper.getWidth(), waterWrapper.getHeight());
            WatermarkParameter param = new WatermarkParameter(waterWrapper, 1f, (int) p.getX(), (int) p.getY());
            BufferedImage bufferedImage = ImageDrawHelper.drawWatermark(imageWrapper.getAsBufferedImage(), param);
            imageWrapper = new ImageWrapper(bufferedImage);
            // 4.输出
            outStream = new FileOutputStream(out);
            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
        } catch (Exception e) {
            logger.error("simpleImageUtil.scaleWithWaterMark异常:" + e.getMessage());
        } finally {
            IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
            IOUtils.closeQuietly(outStream);

        }

    }

    /**
     * 缩放到指定宽度,高度自适应
     *
     * @param src    源文件
     * @param target 目标文件
     * @param width  宽度
     */
    public static void scaleWithWidth(File src, File target, Integer width) {
        doScaleWithWidth(src, target, width);
    }

    /**
     * 缩放到指定宽度,高度自适应
     *
     * @param src    源文件
     * @param target 目标文件
     * @param width  宽度
     */
    public static void scaleWithWidth(String src, String target, Integer width) {
        doScaleWithWidth(new File(src), new File(target), width);
    }


    /**
     * 执行缩放
     */
    private static void doScaleWithWidth(File in, File out, Integer width) {
        FileOutputStream outStream = null;
        FileInputStream inStream = null;
        try {
            inStream = new FileInputStream(in);
            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);

            int w = imageWrapper.getWidth();
            int h = imageWrapper.getHeight();
            // 1.缩放
            ScaleParameter scaleParam;
            if (w < width) {// 如果图片宽和高都小于目标图片则不做缩放处理
                scaleParam = new ScaleParameter(w, h, ScaleParameter.Algorithm.LANCZOS);
            } else {
                int newHeight = getHeight(w, h, width);
                scaleParam = new ScaleParameter(width, newHeight + 1, ScaleParameter.Algorithm.LANCZOS);
            }
            PlanarImage planrImage = ImageScaleHelper.scale(imageWrapper.getAsPlanarImage(), scaleParam);
            imageWrapper = new ImageWrapper(planrImage);
            // 4.输出
            outStream = new FileOutputStream(out);
            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
        } catch (Exception e) {
            logger.error("simpleImageUtil.scaleWithWidth异常:" + e.getMessage());
        } finally {
            IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
            IOUtils.closeQuietly(outStream);

        }
    }
    /**
     * 缩放到指定宽度,高度自适应
     *
     * @param src    源文件
     * @param target 目标文件
     * @param width  宽度
     */
//    private static void doScaleWithWidth(File src, File target, Integer width) {
//        File out = new File(target); // 目的图片
//        FileOutputStream outStream = null;
//        File in = new File(src); // 原图片
//        FileInputStream inStream = null;
//        try {
//            inStream = new FileInputStream(in);
//            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);
//
//            int w = imageWrapper.getWidth();
//            int h = imageWrapper.getHeight();
//            // 1.缩放
//            ScaleParameter scaleParam;
//            if (w < width) {// 如果图片宽和高都小于目标图片则不做缩放处理
//                scaleParam = new ScaleParameter(w, h, ScaleParameter.Algorithm.LANCZOS);
//            } else {
//                int newHeight = getHeight(w, h, width);
//                scaleParam = new ScaleParameter(width, newHeight + 1, ScaleParameter.Algorithm.LANCZOS);
//            }
//            PlanarImage planrImage = ImageScaleHelper.scale(imageWrapper.getAsPlanarImage(), scaleParam);
//            imageWrapper = new ImageWrapper(planrImage);
//            // 4.输出
//            outStream = new FileOutputStream(out);
//            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
//            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
//        } catch (Exception e) {
//            logger.error("simpleImageUtil.scaleWithWidth异常:" + e.getMessage());
//        } finally {
//            IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
//            IOUtils.closeQuietly(outStream);
//
//        }
//
//    }

    /**
     * 缩放到指定高度，宽度自适应
     *
     * @param src    源文件
     * @param target 目标文件
     * @param height 高度
     */
    public static void scaleWithHeight(String src, String target, Integer height) {
        File out = new File(target); // 目的图片
        FileOutputStream outStream = null;
        File in = new File(src); // 原图片
        FileInputStream inStream = null;
        try {
            inStream = new FileInputStream(in);
            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);

            int w = imageWrapper.getWidth();
            int h = imageWrapper.getHeight();
            // 1.缩放
            ScaleParameter scaleParam;
            // 如果图片宽和高都小于目标图片则不做缩放处理
            if (w < height) {
                scaleParam = new ScaleParameter(w, h, ScaleParameter.Algorithm.LANCZOS);

            } else {
                int newWidth = getWidth(w, h, height);
                scaleParam = new ScaleParameter(newWidth + 1, height, ScaleParameter.Algorithm.LANCZOS);

            }
            PlanarImage planrImage = ImageScaleHelper.scale(imageWrapper.getAsPlanarImage(), scaleParam);
            imageWrapper = new ImageWrapper(planrImage);
            // 4.输出
            outStream = new FileOutputStream(out);
            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
        } catch (Exception e) {
            logger.error("simpleImageUtil.scaleWithHeight异常:" + e.getMessage());
        } finally {
            IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
            IOUtils.closeQuietly(outStream);

        }

    }

    /**
     * 从中间裁切需要的大小
     *
     * @param src    源文件
     * @param target 目标文件
     * @param width  宽度
     * @param height 高度
     */
    public static void cutCenter(String src, String target, Integer width, Integer height) {
        File out = new File(target); // 目的图片
        FileOutputStream outStream = null;
        File in = new File(src); // 原图片
        FileInputStream inStream = null;
        try {
            inStream = new FileInputStream(in);
            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);

            int w = imageWrapper.getWidth();
            int h = imageWrapper.getHeight();
            int x = (w - width) / 2;
            int y = (h - height) / 2;

            CropParameter cropParam = new CropParameter(x, y, width, height);// 裁切参数
            if (x < 0 || y < 0) {
                cropParam = new CropParameter(0, 0, w, h);// 裁切参数
            }
            PlanarImage planrImage = ImageCropHelper.crop(imageWrapper.getAsPlanarImage(), cropParam);
            imageWrapper = new ImageWrapper(planrImage);
            // 4.输出
            outStream = new FileOutputStream(out);
            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
        } catch (Exception e) {
            logger.error("simpleImageUtil.CutCenter异常:" + e.getMessage());
        } finally {
            IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
            IOUtils.closeQuietly(outStream);
        }
    }

    /**
     * 裁切 为正文形
     *
     * @param src    源文件
     * @param target 目标文件
     */
    public static void cut(String src, String target) {
        File out = new File(target); // 目的图片
        FileOutputStream outStream = null;
        File in = new File(src); // 原图片
        FileInputStream inStream = null;
        try {
            inStream = new FileInputStream(in);
            ImageWrapper imageWrapper = ImageReadHelper.read(inStream);

            int w = imageWrapper.getWidth();
            int h = imageWrapper.getHeight();
            int width = 0;
            int height = 0;

            if (w >= h) {
                width = h;
                height = h;
            } else {
                width = w;
                height = w;
            }
            CropParameter cropParam = new CropParameter(0, 0, width, height);// 裁切参数
            PlanarImage planrImage = ImageCropHelper.crop(imageWrapper.getAsPlanarImage(), cropParam);
            imageWrapper = new ImageWrapper(planrImage);
            // 4.输出
            outStream = new FileOutputStream(out);
            String prefix = out.getName().substring(out.getName().lastIndexOf(".") + 1);
            ImageWriteHelper.write(imageWrapper, outStream, outputFormat.getImageFormat(prefix), new WriteParameter());
        } catch (Exception e) {
            logger.error("simpleImageUtil.Cut异常:" + e.getMessage());
        } finally {
            IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
            IOUtils.closeQuietly(outStream);
        }
    }


    /**
     * 根据宽、高和目标宽度 等比例求宽度
     *
     * @param sourceWidth  原始宽度
     * @param sourceHeight 原始高度
     * @param targetWidth  目高宽度
     */
    private static Integer getHeight(Integer sourceWidth, Integer sourceHeight, Integer targetWidth) {
        return sourceHeight * targetWidth / sourceWidth;
    }

    /**
     * 根据宽、高和目标宽度 等比例求高度
     *
     * @param sourceWidth  原始宽度
     * @param sourceHeight 原始高度
     * @param targetHeight 目标宽度
     */
    private static Integer getWidth(Integer sourceWidth, Integer sourceHeight, Integer targetHeight) {
        return sourceWidth * targetHeight / sourceHeight;
    }


    /**
     * 计算
     */
    private static Point calculate(int enclosingWidth, int enclosingHeight, int width, int height) {
        int x = (enclosingWidth / 2) - (width / 2);
        int y = (enclosingHeight / 2) - (height / 2);
        return new Point(x, y);
    }

}
